iT邦幫忙

2022 iThome 鐵人賽

DAY 28
0
自我挑戰組

你也對開始使用typescript感到無力嗎?我也是 - 30天初探typescript系列 第 28

第28天!function/arrow function component與泛型組合技練習!

  • 分享至 

  • xImage
  •  

從一開始到這邊,雖然我們已經能大概寫出型別、看出型別,但要與React配合,甚至結合泛型,再順暢切換function component與arrow function component,依然不是這麼容易,今天我們就來做個練習吧!

無型別的function元件

先讓我們看看function版本的寫法,底下我們會弄一個很簡單的元件,沒有什麼複雜的邏輯:

function List({ items, render }) {
  return (
    <ul>
      {items.map((item, index) => (
        <li key={index}>{render(item)}</li>
      ))}
    </ul>
  )
}

我們只是要接收items,跟一個render function,對items進行map方法以後,將render塞進<ul>內的每個<li>而已,這邊key就任意用陣列的索引值帶過吧。
看習慣TypeScript的你(好吧可能還沒),一定不習慣看不到型別的元件,就讓我們先為function版的元件加上型別以及應用泛型吧!非常建議你在還沒看下去之前,思考一下這個function有哪個地方可以加入泛型、讓這個function未來不只一種用途。自己思考過後才會發現從沒想到的盲點!

(防雷)

有型別的function元件

function List<ListItem>({
  items,
  render
}: {
  items: ListItem[]
  render: (item: ListItem) => ReactNode
}) {
  return (
    <ul>
      {items.map((item, index) => (
        <li key={index}>{render(item)}</li>
      ))}
    </ul>
  )
}

寫完了!相信這邊不是太難。跟簡單版的差別就在於:

  1. function名稱後加上一個泛型List<ListItem>,角括號內名字任你取
  2. props({items,render})後面加上型別,items必然是塞了剛剛泛型ListItem的陣列,而render就會需要帶入一個引數(理所當然是單數的ListItem),並回傳一個...ReactNode(因為我們要塞在JSX內)!

寫完後,就能試試將它渲染出來了!你的App.tsx還在嗎?在的話就放進去看看吧,放進去一下下就好~

//在App.tsx內
//略過剛剛寫的List function,你可以引入或直接寫在同個檔案
const App = () => {
    return <List items={[1, 2, 3]} render={(num) => <span>{num}</span>} />
}

我們就能得到一個樸實無華的1,2,3清單囉!那讓我們用const方式寫寫看吧...(想到就頭痛)。

const版(arrow function)元件

const List: <ListItem>({
  items,
  render
}: {
  items: ListItem[]
  render: (item: ListItem) => ReactNode
}) => JSX.Element = ({ items, render }) => {
  return (
    <ul>
      {items.map((item, index) => (
        <li key={index}>{render(item)}</li>
      ))}
    </ul>
  )
}

很(不)明顯的,只有在第一個冒號後、JSX.Element以前的東西,才是TypeScript的內容。在開始寫以前,我沒有想到const版本有這~麼的醜,但意思幾乎是一模一樣的,最大差別在於,const版本必須明確寫出回傳值JSX.Element(如果還不知道為什麼他必須回傳JSX.Element,你可以回去function版的元件,hover在List上面看看!),不然整個型別宣告不會完整。

而我們既然有型別別名的觀念,就能將List的type給獨立創立出來,甚至export到他處使用喔:

export type ListComponent = <ListItem>({
  items,
  render
}: {
  items: ListItem[]
  render: (item: ListItem) => ReactNode
}) => JSX.Element

//再省去return關鍵字,少寫一點點code
const List: ListComponent = ({ items, render }) => (
  <ul>
    {items.map((item, index) => (
      <li key={index}>{render(item)}</li>
    ))}
  </ul>
)

你有發現,這樣比較好讀一~~~~點了嗎?結構看起來清楚多了,type ListComponent其實就只是const版函式的型別宣告,前面掛上一個泛型而已。

就這樣,你成功的從沒有型別的Listfunction元件,寫出了有型別的function元件,再完成了const版複雜一點點點點的元件。第一眼看真的是很醜啦,但稍微靜下心來就能慢慢慢慢的了解他的寫法了,凡事都需要練習囉。

那我們明天見!TGIF!


上一篇
第27天!TypeScript與customHook!
下一篇
第29天!TypeScript番外篇 - Utility Types
系列文
你也對開始使用typescript感到無力嗎?我也是 - 30天初探typescript30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言